#include <stdio.h>
#include <stdlib.h>
#include "md5.c"
#include <string.h>

#define LEN_MD5 16
#define BLOCKSIZE 64

void HMAC_MD5(unsigned char* out, unsigned char* input, int ilen, unsigned char* key, int klen){
    int i;
    char ipad = 0x36;
    char opad = 0x5c;
    MD5_CTX md5;
    
    // 1.对共享密钥 k 左边补0，生成一个 b 位的数据块 K+
    unsigned char step1Result[BLOCKSIZE];
    // 2.K+与 ipad 作 XOR，生成 b 位的 Si
    unsigned char step2Result[BLOCKSIZE];
    // 3.对 (Si ‖ M) 进行 hash 压缩 (例如 MD5)，得到 H(Si ‖ M)
    unsigned char step3Result[LEN_MD5];
    // 4.K+与 opad 作 XOR，生成 b 位的 So
    unsigned char step4Result[BLOCKSIZE];
    // 5.对 So ‖ H(Si ‖ M) 进行 hash 压缩 (例如 MD5)，得到HMACK = H(So ‖ H(Si ‖ M))
    unsigned char step5Result[LEN_MD5];
    
    // Step1.对共享密钥 k 左边补0，生成一个 b 位的数据块 K+；
    for (i = 0; i < BLOCKSIZE; i++){
        step1Result[i] = 0;
    }
    for (i = 0; i < klen; i++){
        step1Result[i] = key[i];
    }
    
    // Step2.K+与 ipad 作 XOR，生成 b 位的 Si； 
    for (i = 0; i < BLOCKSIZE; i++){
        step2Result[i] = step1Result[i] ^ ipad;
    }

    // Step3.对 (Si ‖ M) 进行 hash 压缩 (例如 MD5)，得到 H(Si ‖ M)
    
    // 串接 Si ‖ M
    unsigned char temp[BLOCKSIZE + ilen];
    for (i = 0; i < BLOCKSIZE + ilen; i++){
        if(i >= BLOCKSIZE){
            temp[i] = input[i - BLOCKSIZE];
        }else{
            temp[i] = step2Result[i];
        }
    }
    // MD5压缩
    MD5Init(&md5);         		
	MD5Update( &md5, temp, BLOCKSIZE + ilen);
	MD5Final(&md5, step3Result);

    // Step4.K+与 opad 作 XOR，生成 b 位的 S0
    for ( i = 0 ; i < BLOCKSIZE; i++ ){
		step4Result[i] = step1Result[i] ^ opad;
	}

    // Step5.对 S0 ‖ H(Si ‖ M) 进行 hash 压缩 (例如 MD5)，得到 HMACK = H(So ‖ H(Si ‖ M))
    
    // 串接 S0 ‖ H(Si ‖ M)
    unsigned char temp1[BLOCKSIZE + LEN_MD5];
    for (i = 0; i < BLOCKSIZE + LEN_MD5; i++)
    {
        if(i >= BLOCKSIZE){
            temp1[i] = step3Result[i - BLOCKSIZE];
        }else{
            temp1[i] = step4Result[i];        
        }        
    }
    MD5Init(&md5);         		
	MD5Update( &md5, temp1, BLOCKSIZE + LEN_MD5);
	MD5Final(&md5, out);
}

void TestHMAC_MD5(char* a, char* b){
    int success = 1;
    int i;
    for (i = 0; i < 32; i++)
    {
        if(a[i] != b[i]){
            printf("\n验证失败");
            success = 0;
            break;
        }
    }
    if(success){
        printf("\n验证成功");
    }
}

int main(int argc, char const *argv[])
{
    int i;
    char input[256]; // = "Hello, my name is Enrique";
    char key[256];  // = "Enriqueliu";

    printf("请输入加密的内容 \nM: ");
    gets(input);
    printf("请输入共享密钥 \nkey: ");
    gets(key);

    printf("\n加密后：\n");
    unsigned char *out = (unsigned char *)malloc(16);
    HMAC_MD5(out, (unsigned char *)input , strlen(input), (unsigned char *)key , strlen(key));
    char out1[256];
    char out2[32];    
    for (i = 0; i < 16; i++)
    {
        sprintf(out1, "%02x", out[i]);
        out2[i * 2] = out1[0];
        out2[i * 2 + 1] = out1[1];        
        printf("%02x", out[i]);
    }

    // printf("\n");
    for (i = 0; i < 32; i++)
    {
        out1[i] = out2[i];
    }

    printf("\n\n验证比对 \n请输入网站上HMAC-MD5加密结果：\n");
    char result[32];
    gets(result);

    TestHMAC_MD5(out1, result);

    return 0;
}
